package com.jimmyhsu.ecnudaowei.coursetable.file;

import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.jcodecraeer.xrecyclerview.ProgressStyle;
import com.jcodecraeer.xrecyclerview.XRecyclerView;
import com.jimmyhsu.ecnudaowei.Db.UserDbHelper;
import com.jimmyhsu.ecnudaowei.MyApplication;
import com.jimmyhsu.ecnudaowei.R;
import com.jimmyhsu.ecnudaowei.Utils.DownloadUtils;
import com.jimmyhsu.ecnudaowei.common.Config;
import com.jimmyhsu.ecnudaowei.common.FileOpenHelper;
import com.jimmyhsu.ecnudaowei.common.network.ProgressListener;
import com.jimmyhsu.ecnudaowei.common.network.ProgressRetrofitHelper;
import com.jimmyhsu.ecnudaowei.common.views.GlideRoundTransform;
import com.nbsp.materialfilepicker.MaterialFilePicker;
import com.nbsp.materialfilepicker.ui.FilePickerActivity;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.Query;

public class FileActivity extends AppCompatActivity {

    private static final String EXTRA_COURSE_ID = "extra_course_id";
    private static final int REQUEST_FILE = 1;
    private long fileSize = 0;
    private String mCourseId;
    private List<SharedFile> mSharedFiles = new ArrayList<>();
    private FileAdapter mAdapter;
    private ProgressDialog mProgress;


    @BindView(R.id.toolbar)
    Toolbar mToolbar;
    @BindView(R.id.id_file_recycler)
    XRecyclerView mFileListView;

    private FileHandler mFileHandler;
    private ExecutorService mThreadPool;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file);
        ButterKnife.bind(this);
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        setTitle("文件");
        initRecyclerView();
        initProgressDialog();
        loadDataFromIntent();
    }

    private void initProgressDialog() {
        mProgress = new ProgressDialog(this);
        mProgress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mProgress.setIndeterminate(false);
        mProgress.setCancelable(false);
        mProgress.setCanceledOnTouchOutside(false);
    }

    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
        mThreadPool = Executors.newFixedThreadPool(1);
        loadDataFromDb();
        loadDataFromServer();
    }

    private void initRecyclerView() {
        mFileListView.setAdapter(mAdapter = new FileAdapter(this));
        mFileListView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        mFileListView.setLoadingMoreEnabled(false);
        mFileListView.setPullRefreshEnabled(true);
        mFileListView.setRefreshProgressStyle(ProgressStyle.Pacman);
        mFileListView.setLoadingListener(new XRecyclerView.LoadingListener() {
            @Override
            public void onRefresh() {
                loadDataFromServer();
            }

            @Override
            public void onLoadMore() {

            }
        });
        mFileHandler = new FileHandler(this);
    }

    @OnClick(R.id.fab)
    void chooseFileAndUpload() {
        new MaterialFilePicker()
                .withActivity(this)
                .withRequestCode(REQUEST_FILE)
                .withFilterDirectories(true)
                .withHiddenFiles(true)
                .start();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_FILE && resultCode == RESULT_OK) {
            String filePath = data.getStringExtra(FilePickerActivity.RESULT_FILE_PATH);
            uploadFile(filePath);
        }
    }

    private void uploadFile(String filePath) {
        MyApplication app = MyApplication.getInstance(this);
        File file = new File(filePath);
        if (!file.exists() || file.isDirectory()) {
            Snackbar.make(mFileListView, "不支持文件夹上传", Snackbar.LENGTH_SHORT).show();
            return;
        }
        if (file.length() >= 102400000) {
            Snackbar.make(mFileListView, "文件最大100MB", Snackbar.LENGTH_SHORT).show();
            return;
        }
        fileSize = file.length();
        mProgress.setTitle("上传");
        mProgress.show();
        RequestBody requestFile =
                RequestBody.create(MediaType.parse("application/otcet-stream"), file);
        MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
        UploadFileService uploadFileService = new Retrofit.Builder()
                .baseUrl(Config.SERVER_URL)
                .client(ProgressRetrofitHelper.getUploadProgressClient(new ProgressListener() {
                    @Override
                    public void onProgress(long progress, long total, boolean done) {
                        mProgress.setMax((int) fileSize);
                        mProgress.setProgress((int) progress);
                    }
                }))
                .addConverterFactory(ScalarsConverterFactory.create())
                .build()
                .create(UploadFileService.class);
        Call<String> call = uploadFileService.uploadFile(DownloadUtils.getFormRequestBody(app.getName()),
                DownloadUtils.getFormRequestBody(app.getPassword()),
                DownloadUtils.getFormRequestBody(mCourseId),
                body);
        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                if (response.code() == 200) {
                    String resp = response.body();
                    if (resp.equals("success")) {
                        Toast.makeText(FileActivity.this, "上传成功", Toast.LENGTH_SHORT).show();
                        mThreadPool.submit(new GetFileListFromServerRunnable());
                    } else if (resp.equals("permission denied")) {
                        Toast.makeText(FileActivity.this, "只有管理员才能上传哦", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(FileActivity.this, "上传失败", Toast.LENGTH_SHORT).show();
                    }
                }
                mProgress.hide();
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                Toast.makeText(FileActivity.this, "上传失败", Toast.LENGTH_SHORT).show();
                mProgress.hide();
            }
        });
    }

    private void loadDataFromDb() {
        mThreadPool.submit(new GetFileListFromDbRunnable());
    }

    private void loadDataFromServer() {
        mThreadPool.submit(new GetFileListFromServerRunnable());
    }

    private void loadDataFromIntent() {
        mCourseId = getIntent().getStringExtra(EXTRA_COURSE_ID);
    }

    private static class FileAdapter extends RecyclerView.Adapter<FileHolder> implements ProgressListener {

        private WeakReference<FileActivity> mActivityReference;
        private LayoutInflater mInflater;

        FileAdapter(FileActivity activity) {
            mActivityReference = new WeakReference<>(activity);
            mInflater = LayoutInflater.from(activity.getApplicationContext());
        }

        @Override
        public FileHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            final View convertView = mInflater.inflate(R.layout.file_item, parent, false);
            convertView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int pos = (int) convertView.getTag();
                    downloadFile(pos);
                }
            });
            return new FileHolder(convertView);
        }

        private void downloadFile(final int pos) {
            final SharedFile sharedFile = mActivityReference.get().mSharedFiles.get(pos);
            final String target = sharedFile.getName() + "." + sharedFile.getType();
//            if (new File(Environment.getExternalStorageDirectory() + "/SuperSyllabus/" + target).exists()) {
//                openFile(new File(Environment.getExternalStorageDirectory() + "/SuperSyllabus/"
//                        + sharedFile.getName() + "." + sharedFile.getType()));
//                return;
//            }
            if (sharedFile.isDownloaded()) {
                File file = new File(Environment.getExternalStorageDirectory() + "/SuperSyllabus/"
                        + sharedFile.getName() + "." + sharedFile.getType());
                if (file.exists()) {
                    openFile(file);
                    return;
                } else {
                    Toast.makeText(mActivityReference.get(), "文件移动或被删除，重新下载中", Toast.LENGTH_SHORT).show();
                    setDownloaded(pos, false);
                }
            }
            String url = sharedFile.getUrl();
            mActivityReference.get().fileSize = sharedFile.getSize();
            DownloadFileService downloadService = new Retrofit.Builder()
                    .baseUrl(Config.SERVER_URL)
                    .client(ProgressRetrofitHelper.getProgressClient(this))
                    .build()
                    .create(DownloadFileService.class);
            Call<ResponseBody> call = downloadService.downloadFile(url, target);
            mActivityReference.get().mProgress.setTitle("下载");
            call.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                    try {
                        InputStream is = response.body().byteStream();
                        File file = new File(Environment.getExternalStorageDirectory() + "/SuperSyllabus/" + target);
                        if (!file.getParentFile().exists()) {
                            file.getParentFile().mkdir();
                        } else if (file.exists()) {
                            file.delete();
                        }
                        FileOutputStream fos = new FileOutputStream(file);
                        BufferedInputStream bis = new BufferedInputStream(is);
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = bis.read(buffer)) != -1) {
                            fos.write(buffer, 0, len);
                            fos.flush();
                        }
                        fos.close();
                        bis.close();
                        is.close();
                        Toast.makeText(mActivityReference.get(), "下载完成", Toast.LENGTH_SHORT).show();
                        setDownloaded(pos, true);
                        sharedFile.setDownloaded(true);
                        notifyDataSetChanged();
                        openFile(file);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    mActivityReference.get().mProgress.hide();
                }

                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {
                    Toast.makeText(mActivityReference.get(), "下载失败", Toast.LENGTH_SHORT).show();
                    mActivityReference.get().mProgress.hide();
                }
            });
            mActivityReference.get().mProgress.show();
        }

        private void openFile(File file) {
            FileOpenHelper.openFile(mActivityReference.get(), file);
        }

        private void setDownloaded(int pos, boolean downloaded) {
            SharedFile file = mActivityReference.get().mSharedFiles.get(pos);
            SQLiteDatabase db = UserDbHelper.getInstance(mActivityReference.get()).getWritableDatabase();
            db.execSQL("update sharedfile set downloaded=" + (downloaded?1:0) + " where url='" + file.getUrl() + "'");
            db.close();
        }

        @Override
        public void onBindViewHolder(FileHolder holder, int position) {
            holder.contentView.setTag(position);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日");
            SharedFile file = mActivityReference.get().mSharedFiles.get(position);
            holder.fileNameView.setText(file.getName());
            holder.publisherView.setText(file.getPublisher());
            holder.timeView.setText(sdf.format(new Date(file.getReleaseTime())));
            holder.fileSizeView.setText(getSizeText(file.getSize()));
            Glide.with(mActivityReference.get()).load(getFileTypeIcon(file.getType()))
                    .transform(new GlideRoundTransform(mActivityReference.get(), 2)).into(holder.fileTypeView);
            holder.fileTypeView.setImageResource(getFileTypeIcon(file.getType()));
//            File f = new File(Environment.getExternalStorageDirectory() + "/SuperSyllabus/"
//                    + file.getName() + "." + file.getType());
//            if (f.exists()) {
//                holder.fileDownloaded.setVisibility(View.VISIBLE);
//            } else {
//                holder.fileDownloaded.setVisibility(View.GONE);
//            }
            if (file.isDownloaded()) {
                holder.fileDownloaded.setVisibility(View.VISIBLE);
            } else {
                holder.fileDownloaded.setVisibility(View.GONE);
            }
        }

        private String getSizeText(int sizeInBytes) {
            if (sizeInBytes < 1024) {
                return sizeInBytes + "B";
            } else if (sizeInBytes < 1024 * 1024) {
                return String.format("%.1f", sizeInBytes / 1024f) + "KB";
            } else if (sizeInBytes < 1024 * 1024 * 1024) {
                return String.format("%.1f", sizeInBytes / (1024f * 1024)) + "MB";
            } else {
                return String.format("%.1f", sizeInBytes / (1024f * 1024 * 1024)) + "GB";
            }
        }

        private int getFileTypeIcon(String type) {
            switch (type) {
                case "docx":
                case "doc":
                    return R.drawable.word;
                case "ppt":
                case "pptx":
                    return R.drawable.ppt;
                case "xls":
                case "xlsx":
                    return R.drawable.excel;
                case "mp4":
                case "mov":
                case "avi":
                case "rmvb":
                case "vob":
                case "3gp":
                case "rm":
                case "wmv":
                    return R.drawable.mp4;
                case "mp3":
                case "aac":
                    return R.drawable.mp3;
                case "zip":
                case "rar":
                case "7z":
                case "gz":
                    return R.drawable.zip;
                default:
                    return R.drawable.fileunknown;
            }
        }

        @Override
        public int getItemCount() {
            return mActivityReference.get().mSharedFiles.size();
        }

        @Override
        public void onProgress(long progress, long total, boolean done) {
            EventBus.getDefault().post(new ProgressEvent(progress, total, done));
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        mThreadPool.shutdownNow();
        EventBus.getDefault().unregister(this);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onProgressUpdate(ProgressEvent event) {
        if (!mProgress.isShowing()) return;
        mProgress.setMax((int) fileSize);
        mProgress.setProgress((int) event.progress);
        Log.e("haha", "progress: " + event.progress + ", " + event.total);
    }

    private static class ProgressEvent {
        long progress;
        long total;
        boolean done;

        public ProgressEvent(long progress, long total, boolean done) {
            this.progress = progress;
            this.total = total;
            this.done = done;
        }
    }

    static class FileHolder extends RecyclerView.ViewHolder {
        View contentView;
        @BindView(R.id.id_file_name)
        TextView fileNameView;
        @BindView(R.id.id_file_type)
        ImageView fileTypeView;
        @BindView(R.id.id_file_size)
        TextView fileSizeView;
        @BindView(R.id.id_file_publisher)
        TextView publisherView;
        @BindView(R.id.id_file_time)
        TextView timeView;
        @BindView(R.id.id_file_downloaded)
        ImageView fileDownloaded;
        public FileHolder(View itemView) {
            super(itemView);
            this.contentView = itemView;
            ButterKnife.bind(this, itemView);
        }
    }

    class GetFileListFromDbRunnable implements Runnable {
        @Override
        public void run() {
            SQLiteDatabase db = UserDbHelper.getInstance(FileActivity.this).getReadableDatabase();
            Cursor cursor = db.query(SharedFile.TABLE_NAME, null, "? = ?", new String[]{SharedFile.COL_COURSE_ID, mCourseId},
                    null, null, SharedFile.COL_TIME + " desc");
            mSharedFiles.clear();
            while (cursor.moveToNext()) {
                mSharedFiles.add(new SharedFile(cursor.getString(cursor.getColumnIndex(SharedFile.COL_TYPE)),
                        cursor.getString(cursor.getColumnIndex(SharedFile.COL_TITLE)),
                        cursor.getInt(cursor.getColumnIndex(SharedFile.COL_SIZE)),
                        cursor.getString(cursor.getColumnIndex(SharedFile.COL_AUTHOR)),
                        cursor.getLong(cursor.getColumnIndex(SharedFile.COL_TIME)),
                        cursor.getString(cursor.getColumnIndex(SharedFile.COL_URL)),
                        cursor.getInt(cursor.getColumnIndex(SharedFile.COL_DOWNLOADED))));
            }
            cursor.close();
            mFileHandler.sendEmptyMessage(0x110);
        }
    }

    class GetFileListFromServerRunnable implements Runnable {

        @Override
        public void run() {
            MyApplication app = MyApplication.getInstance(FileActivity.this);
            GetFileListService service = new Retrofit.Builder().baseUrl(Config.SERVER_URL)
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .build()
                    .create(GetFileListService.class);
            Call<String> call = service.getFileList(app.getName(),
                    app.getPassword(),
                    mCourseId);
            call.enqueue(new Callback<String>() {
                @Override
                public void onResponse(Call<String> call, Response<String> response) {
                    if (response.code() == 200) {
                        UserDbHelper helper = UserDbHelper.getInstance(FileActivity.this);
                        SQLiteDatabase db = helper.getWritableDatabase();
                        List<String> downloadedUrls = getDownloadedUrls(db);
                        db.execSQL("delete from sharedfile where course_id='" + mCourseId + "'");
                        try {
                            JSONObject responseObj = new JSONObject(response.body());
                            if (responseObj.getInt("code") == 200) {
                                mSharedFiles.clear();
                                JSONArray dataArr = responseObj.getJSONArray("data");
                                int length = dataArr.length();
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                for (int i = 0; i < length; i++) {
                                    JSONObject fileEntity = dataArr.getJSONObject(i);
                                    ContentValues values = new ContentValues();
                                    String url = fileEntity.getString("url");
                                    int downloaded = downloadedUrls.contains(url)?1:0;
                                    SharedFile file = new SharedFile(fileEntity.getString("type"),
                                            fileEntity.getString("title"),
                                            fileEntity.getInt("size"),
                                            fileEntity.getString("author"),
                                            sdf.parse(fileEntity.getString("release_time")).getTime(),
                                            url,
                                            downloaded);
                                    values.put(SharedFile.COL_COURSE_ID, mCourseId);
                                    values.put(SharedFile.COL_URL, fileEntity.getString("url"));
                                    values.put(SharedFile.COL_AUTHOR, file.getPublisher());
                                    values.put(SharedFile.COL_SIZE, file.getSize());
                                    values.put(SharedFile.COL_TIME, file.getReleaseTime());
                                    values.put(SharedFile.COL_TYPE, file.getType());
                                    values.put(SharedFile.COL_TITLE, file.getName());
                                    values.put(SharedFile.COL_DOWNLOADED, downloaded);
                                    db.insert(SharedFile.TABLE_NAME, null, values);
                                    mSharedFiles.add(file);
                                }
                                mFileHandler.sendEmptyMessage(0x110);
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        } catch (ParseException e) {
                            e.printStackTrace();
                        } finally {
                            db.close();
                        }
                    } else {
                        Snackbar.make(mFileListView, "服务器异常", Snackbar.LENGTH_SHORT).show();
                    }
                    mFileListView.refreshComplete();
                }

                @Override
                public void onFailure(Call<String> call, Throwable t) {
                    mFileListView.refreshComplete();
                    Snackbar.make(mFileListView, "网络异常", Snackbar.LENGTH_SHORT).show();
                }
            });
        }
    }

    private List<String> getDownloadedUrls(SQLiteDatabase db) {
        List<String> downloadedUrls = new ArrayList<>();
        Cursor cursor = db.rawQuery("select url from sharedfile where course_id='" + mCourseId + "' and " +
                "downloaded>0", null);
        while (cursor.moveToNext()) {
            downloadedUrls.add(cursor.getString(cursor.getColumnIndex(SharedFile.COL_URL)));
        }
        cursor.close();
        return downloadedUrls;
    }

    private static class FileHandler extends Handler {

        private WeakReference<FileActivity> mActivityReference;

        public FileHandler(FileActivity activity) {
            super(Looper.getMainLooper());
            mActivityReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mActivityReference.get().mAdapter.notifyDataSetChanged();
        }
    }

    interface GetFileListService {
        @FormUrlEncoded
        @POST("phpprojects/course/getSharedFiles.php")
        Call<String> getFileList(@Field("username") String username,
                                 @Field("password") String password,
                                 @Field("course_id") String courseId);

    }

    interface DownloadFileService {
        @GET("phpprojects/Teacher/downloadService.php")
        Call<ResponseBody> downloadFile(@Query("filename") String fileName,
                                        @Query("outfile_name") String outFileName);
    }

    interface UploadFileService {
        @Multipart
        @POST("phpprojects/course/studentFileUpload.php")
        Call<String> uploadFile(@Part("username") RequestBody username,
                                @Part("password") RequestBody password,
                                @Part("course_id") RequestBody courseId,
                                @Part() MultipartBody.Part file);
    }

    public static void startActivity(Context context, String courseId) {
        context.startActivity(new Intent(context, FileActivity.class)
                .putExtra(EXTRA_COURSE_ID, courseId));
    }

}
